package ch.coredump.tagcloud.data;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.logging.Logger;

import ch.coredump.tagcloud.CloudSettings;
import ch.coredump.tagcloud.util.CloudUtil;

public class FileDataProvider {
	private Logger log = Logger.getLogger(FileDataProvider.class.getName());
	private List<CloudWord> words = new ArrayList<CloudWord>();
	private CloudSettings settings = CloudSettings.instance();

	/**
	 * parses the File or Files inside a directory recursively.
	 * 
	 * @param file
	 */
	public void parse(File file) {
		if (file == null) {
			// nothing to parse
			return;
		}

		if (file.isDirectory()) {
			parseDirectory(file);
		}
		if (file.isFile()) {
			parseFile(file);
		}
	}

	/**
	 * search for files inside the given directory.
	 * 
	 * @param directory
	 *            directory to search for files
	 */
	private void parseDirectory(File directory) {
		if (directory.isDirectory() == false) {
			log.warning(directory.getPath() + " is not a folder");
			return;
		}

		File[] files = directory.listFiles(new FileFilter() {
			@Override
			public boolean accept(File pathname) {
				if (pathname.isDirectory()) {
					return true;
				}
				if (!pathname.getName().endsWith(settings.getFileExtension())) {
					return false;
				}
				return true;
			}
		});

		for (File f : files) {
			if (f.isDirectory()) {
				parseDirectory(f);
			} else if (f.isFile()) {
				parse(f);
			}
		}
	}

	/**
	 * Parses a file and builds a CloudWord List
	 * 
	 * @param file
	 */
	private void parseFile(File file) {
		HashMap<String, Integer> tmpMap = new HashMap<String, Integer>();

		Scanner scanner = null;
		try {
			scanner = new Scanner(file);
			scanner.useDelimiter(CloudUtil.createRegexPattern(CloudSettings
					.instance().getSeperators()));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		int found = 0;
		while (scanner.hasNext()) {
			String next = scanner.next();
			next = next.trim();
			if (next.isEmpty()) {
				continue;
			}
			if (isValidWord(next) != true) {
				log.info("ignoring :" + next);
				continue;
			}

			Integer count = tmpMap.get(next);
			if (count != null) {
				count++;
			} else {
				count = 1;
			}
			tmpMap.put(next, count);
			log.info("found string:" + next + " " + count + " times");

			// stop if max words is reached
			found++;
			if (found >= CloudSettings.instance().getMaxWordsOndisplay()) {
				break;
			}
		}

		// add all found words to the CloudWord List
		for (Entry<String, Integer> e : tmpMap.entrySet()) {
			words.add(new CloudWord(e.getKey(), e.getValue()));
		}

		DataProviderManager.getInstance().calculateWeight(words);
	}

	/**
	 * Checks if this is a valid word. requirements for valid words:<br>
	 * - at least 3 characters long<br>
	 * - word is not in the list of words to ignore
	 */
	private boolean isValidWord(String word) {
		Collection<String> wordstoIgnore = CloudSettings.instance()
				.getWordsToIgnore();
		if (word.length() < settings.getMinWordLength()) {
			log.warning(word + " is too short - ignored");
			return false;
		}
		if (wordstoIgnore.contains(word)) {
			// ignore this word
			return false;
		}
		return true;
	}

	public void reset() {
		words.clear();
	}

	public List<CloudWord> getWords() {
		return words;
	}
}
